import random
import time
import xml.etree.ElementTree as ET
from .extract import extract
from .generate_node import generate_node_hierarchy
from .change_status import make_active_node
from .get_ancestor import get_ancestor
import copy
from .const_args import Dist
from .process_data import process_data

def simulation(tasks,nodes,basic_nodes0):

    task_fail = False  # 如果任务失败更新为True    
    ''' 2024/8/13，不再将“总体”与其它逻辑区分而输出
    system_name = ''

    for node in nodes:
        if node.is_sys:
            system_name = node.name
    '''
    '''
    合并同名节点，以方便同一节点在不同任务中更新
    name 记录名字
    failure_time 在每次节点维修后记录之，以便在任务结束时计算修好后使用了多久
    '''
    # # # print(f"该模型所有根节点{[node0.name for node0 in basic_nodes0]}")
    '''
    创建一个空的嵌套列表 24/8/15 data_f 是存储失败相关节点的，如果节点与导致失败相关，data_f[key]=[1]
    '''
    data = {node.name: [] for node in nodes if node.node_type is not None}
    data['Overall_Task']=[]
    data_f = {node.name: [] for node in nodes if node.node_type is not None}
    data_f['Overall_Task']=[]
    '''
    运行多个任务前的初始化
    '''
    for id in basic_nodes0:
        basic_nodes0[id].status = "Dormant"
        basic_nodes0[id].failure_time = 0
        basic_nodes0[id].is_used = False
        basic_nodes0[id].prob = random.random()
        basic_nodes0[id].repair_time = 0
        basic_nodes0[id].last_failure_dist = None
    '''
    运行多个任务
    '''

    task_count = 1  # 记录当前任务阶段

    for task in tasks:
        for key in data:
            data[key].append([])
        ''' 2024/8/13，不再将“总体”与其它逻辑区分而输出
        if not task_fail:
            data[system_name][task_count - 1].append(('Active', 0.0))
        else:
            data[system_name][task_count - 1].append(('Failed', 0.0))
        '''
        if not task_fail:
            data['Overall_Task'][task_count - 1].append(('Active', 0.0))
        else:
            data['Overall_Task'][task_count - 1].append(('Failed', 0.0))
        duration = task.duration
        duration0 = duration  # 便于计算已经经历的时间

        nam_names = task.nam_names
        for id in basic_nodes0:
            node0 = basic_nodes0[id]
            if node0.status == 'CycDown' or node0.status == 'CycOn':
                node0.status = 'Active'

            node0.AM = True
            if node0.name in nam_names:
                node0.AM = False
            
            if node0.AM:
                if node0.status == "NAM":
                    node0.status = "Maintenance"
            else:
                if node0.status == "Maintenance":
                    node0.status = "NAM"

        model_name = task.model_name

        task_model = next((node for node in nodes if node.name == model_name), None)

        for node in nodes:
            if node.parent and len(node.children)!=0 and not node.is_basic:
                node.is_used = False
                ancestors = get_ancestor(node)
                if task_model in ancestors:
                    node.is_used = True

        basic_nodes = task_model.find_basic()
        # # # # print(f"该模型涉及的基节点: {[node.name for node in basic_nodes]}")
        for node in basic_nodes:
            node0 = basic_nodes0[node.name]
            node.status = node0.status

            node0.failure_dist = node.failure_dist  # 获取当前节点失效类型，原节点类型将在每个任务结束时更新
            node0.repair_dist = node.repair_dist

            node0.parent = node.parent  # node0会将node的parent当成自己的，而那个parent不会认这个孩子
            node0.is_used = True
            
        make_active_node(task_model, basic_nodes)  # 尝试激活任务，这一步会改变basic_nodes中的节点状态
        if task_fail:
            task_model.status = 'Failed'

        for node in nodes:
            now_state = node.update_status()
            #if now_state == 'Dormant':
            #    now_state = 'Active'
            #if node.node_type is not None and node.name != system_name and node.is_basic is False and node.is_used:
            if node.node_type and not node.is_basic and node.is_used:
                data[node.name][task_count - 1].append((now_state, duration0-duration))
            
        for id in basic_nodes0:
            node0 = basic_nodes0[id]
            for node in basic_nodes:
                if node.name == id:
                    node0.status = node.status  # 将改变的basic_nodes中的节点状态返回到basic_nodes0
                    node0.failure_rate = node.failure_rate
                    node0.is_cyc = node.is_cyc
                    node0.cyc[0] = node.cyc[0]
                    node0.cyc[1] = node.cyc[1]
                    node0.cyc[2] = node.cyc[2]
        '''  
        可以改成下面这样，实测时间差不多
        for node in basic_nodes:
            node0 = basic_nodes0[node.name]
            node0.status = node.status
            node0.failure_rate = node.failure_rate
            node0.is_cyc = node.is_cyc
            node0.cyc = list(node.cyc)  # 直接复制整个循环信息列表
        '''
        for id in basic_nodes0:
            node0 = basic_nodes0[id]
            if node0.is_used:
                status = node0.status
                if status == 'Active' and node0.is_cyc:
                    status = 'CycOn'
                data[node0.name][task_count-1].append((status, duration0-duration))
            if node0.is_used and node0.failure_dist.disttype == Dist.sof:
                node0.failure_time,node0.repair_time= node0.get_failure_time_sof(duration0)
            else:
                if node0.status == "Active":
                    if node0.failure_dist.disttype == Dist.binomial:  # 离散型分布的寿命与任务时间有关，另用函数
                        node0.failure_time_m = node0.failure_time  # 记录上个阶段结束时的寿命
                        node0.failure_time = node0.get_failure_time_b(duration0)
                    elif node0.failure_dist.disttype == Dist.bernoulli:
                        node0.failure_time_m = node0.failure_time  # 记录上个阶段结束时的寿命
                        node0.failure_time = node0.get_failure_time_b(duration0)
                    else:
                        node0.failure_time = node0.get_failure_time()
                    
                    if node0.is_cyc:
                        node0.cyc[2] = node0.cyc[0]
                        node0.status = 'CycOn'
                        # 记得同步回node 7.23
                        for node in basic_nodes:
                            if node.name == node0.name:
                                node.status=node0.status
                elif node0.status == "Warm":
                    node0.failure_time = node0.get_failure_time() / node0.failure_rate
                elif node0.status == "Dormant":  # 对于那些开启后在某个阶段休眠的节点，他不会从active变回dormant，但是时间会暂停
                    node0.failure_time = node0.get_failure_time() #11.22 对于休眠节点，决定予以寿命但不会随时间流逝
        
        # print(f"节点名称: {[basic_nodes0[id].name for id in basic_nodes0]}")
        # print(f"节点使用: {[basic_nodes0[id].is_used for id in basic_nodes0]}")
        # print(f"节点状态: {[basic_nodes0[id].status for id in basic_nodes0]}")
        # node0.repair_time = 0
        # print(f"剩余寿命: {[f'{basic_nodes0[id].failure_time:.2f}' for id in basic_nodes0]}")
        # print(f"维修所需: {[f'{basic_nodes0[id].repair_time:.2f}' for id in basic_nodes0]}")
        # print()
        
        task_model.status = task_model.update_status()
        if task_model.status == 'Failed':
            if not task_fail:
                #data[system_name][task_count - 1].append(('Failed', float(duration0-duration)))
                data['Overall_Task'][task_count - 1].append(('Failed', float(duration0-duration)))
                task_fail = True
                # # # print("任务失败")
                # model_continue = False
                # 在该任务的0.0失败即不满足任务初始条件
                # break
        # print(f"当前模型状态: {task_model.status}，任务剩余时间：{duration}")

        event_count = 0  # 记录事件数，事件是指basic节点发生变化
        task_time = 0  # 本task已经运行的时间
        # print(f"节点名称: {[basic_nodes0[id].name for id in basic_nodes0]}")
        # print(f"节点状态: {[basic_nodes0[id].status for id in basic_nodes0]}")
        # node0.repair_time = 0
        # print(f"剩余寿命: {[f'{basic_nodes0[id].failure_time:.2f}' for id in basic_nodes0]}")
        # print()

        while duration > 0:
            update_time = []  # 每个基节点更新状态的时间（损坏、修复），任务剩余时间
            for id in basic_nodes0:
                node0 = basic_nodes0[id]
                node0.change_in_event = False
                if node0.status == 'Active' or node0.status == 'Warm':
                    update_time.append(node0.failure_time)
                elif node0.status == 'CycOn':
                    update_time.append(node0.failure_time)
                    if node0.cyc[2] > 0:
                        update_time.append(node0.cyc[2])
                elif node0.status == 'CycDown':
                    if node0.cyc[2] > 0:
                        update_time.append(node0.cyc[2])
                elif node0.status == 'Maintenance':
                    update_time.append(node0.repair_time)
                elif node0.status == 'Dormant' or node0.status == 'Failed' or node0.status == 'NAM' or node0.status == 'Maintenance_SOF':
                    pass
                else:
                    raise ValueError(f"未知节点状态: {node0.status}")

            update_time.append(duration)
            
            event_time = min(update_time)  # 事件之间的时间间隔，包括未使用节点的变化也视为事件


            duration -= event_time

            event_count += 1
            task_time += event_time
            # print(f"在{task_time:.2f}时间，事件{event_count}发生")

            for id in basic_nodes0:
                node0 = basic_nodes0[id]
                if (node0.status == 'Active' or node0.status == 'Warm') and (node0.is_used or not node0.is_restable):  # Active状态的 使用中 或者 无休 的节点
                    node0.failure_time -= event_time
                elif node0.status == 'CycOn' and (node0.is_used or not node0.is_restable):
                    node0.failure_time -= event_time
                    node0.cyc[2] -= event_time
                elif node0.status == 'CycDown' and (node0.is_used or not node0.is_restable):
                    node0.cyc[2] -= event_time
                elif node0.status == 'Maintenance':
                    node0.repair_time -= event_time
                elif node0.status == 'Dormant' or node0.status == 'Failed' or node0.status == 'NAM' or node0.status == 'Maintenance_SOF':
                    pass
                else:
                    raise ValueError(f"未知节点状态: {node0.status}")

            for id in basic_nodes0:
                node0 = basic_nodes0[id]
                if node0.status == 'CycOn' and (node0.is_used or not node0.is_restable) and node0.failure_time == 0:
                    node0.status = 'Active'
                if node0.status in ['Active', 'Warm'] and (node0.is_used or not node0.is_restable):
                    if node0.failure_time == 0:  # 发生故障事件
                        node0.last_failure_dist = None

                        # # # print(f"基节点{node0.name}故障")
                        if node0.repair_dist and node0.failure_dist.disttype != 'sof':
                            node0.status = 'Maintenance'
                            node0.repair_time = node0.get_repair_time()
                            # # # print(f"基节点{node0.name}将在{node0.repair_time:.2f}后完成维修,{task_time}")
                            if not node0.AM:
                                node0.status = 'NAM'
                            # # # print(f"基节点{node0.name}不可维修")
                        elif node0.failure_dist.disttype == 'sof':
                            node0.status = 'Maintenance_SOF'
                        else:
                            node0.status = 'Failed'
                            node0.repair_time = -1
                        for node in basic_nodes:
                            if node.name == id:
                                node.status = node0.status   # 将node0的状态同步回node
                                break
                        # standby的子节点需要额外判断
                        if task_fail is False:
                            ancestors = get_ancestor(node0)  # 找到 standby 类型的节点
                            ancestors.reverse()
                            basic_nodes_of_ancestor=[]
                            for ancestor in ancestors:
                                if ancestor.node_type == 'standby' or ancestor.node_type == 'warm_standby':
                                    basic_nodes_of_ancestor = ancestor.find_basic()
                                    make_active_node(ancestor, basic_nodes)
                                    break
                                
                            for child_node in basic_nodes_of_ancestor:
                                node00 = basic_nodes0[child_node.name]
                                node00.status = child_node.status
                                node00.change_in_event = child_node.change_in_event
                                child_node.change_in_event = False
                                if node00.change_in_event:
                                    node00.last_event_time = None       #24.11.22确保寿命正常获取
                                    node00.change_in_event = False      #24.11.22修改一个小问题
                                    if node00.status == 'Warm' and node00.failure_time == 0:
                                        if node00.failure_dist.disttype == Dist.binomial or node00.failure_dist.disttype == Dist.bernoulli:  # 离散型分布的寿命与任务时间有关，另用函数
                                            node00.failure_time = node00.get_failure_time_b(duration0)
                                        else:
                                            node00.failure_time = node00.get_failure_time()
                                        node00.failure_time = node00.get_failure_time()/node00.failure_rate
                                    elif node00.status == 'Active' and node00.failure_time == 0:
                                        if node00.failure_dist.disttype == Dist.binomial or node00.failure_dist.disttype == Dist.bernoulli:  # 离散型分布的寿命与任务时间有关，另用函数
                                            node00.failure_time = node00.get_failure_time_b(duration0)
                                        else:
                                            node00.failure_time = node00.get_failure_time()
                                    elif node00.status == 'Active' and node00.failure_time != 0:
                                        node00.failure_time = node00.failure_time * node00.failure_rate

                elif node0.status == 'CycOn' and (node0.is_used or not node0.is_restable):
                    if node0.cyc[2] == 0.0:
                        node0.status = 'CycDown'
                        node0.cyc[2] = node0.cyc[1]
                        for node in basic_nodes:  
                            if node.name == node0.name:
                                node.status = node0.status  # 将node0的状态同步回node
                elif node0.status == 'CycDown' and (node0.is_used or not node0.is_restable):
                    if node0.cyc[2] == 0.0:
                        node0.status = 'CycOn'
                        node0.cyc[2] = node0.cyc[0]
                        for node in basic_nodes:  
                            if node.name == node0.name:
                                node.status = node0.status  # 将node0的状态同步回node
                elif node0.status == 'Maintenance' and node0.repair_time == 0:
                    # print(f"基节点{node0.name}完成维修")
                    node0.last_failure_dist = None  # 将失效模型改为None
                    node0.prob = random.random()   # 在维修后更新 prob
                    node0.cyc[2] = 0    # 在维修后更新循环情况
                    if node0.is_used is True:
                        node0.status = 'Active'
                        
                        ancestors = get_ancestor(node0)
                        for ancestor in ancestors:
                            if ancestor.node_type == 'standby':
                                ancestor_status = ancestor.update_status()
                                if ancestor_status == 'Active':
                                    node0.status = 'Dormant'
                                    ancestors2 = get_ancestor(node0,ancestor)
                                    if ancestors2 != []:
                                        for ancestor2 in ancestors2:
                                            if ancestor2.status =='Active':
                                                node0.status = 'Active'
                                break
                            elif ancestor.node_type == 'warm_standby':
                                ancestor_status = ancestor.update_status()
                                if ancestor_status == 'Active':
                                    node0.status = 'Warm'
                                    ancestors2 = get_ancestor(node0,ancestor)
                                    if ancestors2 != []:
                                        for ancestor2 in ancestors2:
                                            if ancestor2.status =='Active':
                                                node0.status = 'Active'
                                break
                          # 没写好，目前只要有祖先是standby且祖先正常，就会进入休眠，实际上它可能是该祖先下的一个Active结构的一部分，应该被激活
                    else:
                        node0.status = 'Dormant'

                    if node0.status == 'Active':
                        if node0.failure_dist.disttype == Dist.binomial or node0.failure_dist.disttype == Dist.bernoulli:  # 离散型分布的寿命与任务时间有关，另用函数
                            node0.failure_time = node0.get_failure_time_b(duration0)
                        else:
                            node0.failure_time = node0.get_failure_time()
                    elif node0.status == 'Warm':
                        node0.failure_time = node0.get_failure_time()/node0.failure_rate

                    if node0.status == 'Active' and node0.is_cyc:
                        node0.status = 'CycOn'
                        node0.cyc[2] = node0.cyc[0]

                    for node in basic_nodes:  
                        if node.name == node0.name:
                            node.status = node0.status  # 将node0的状态同步回node

            for id in basic_nodes0:
                node0 = basic_nodes0[id]
                if node0.is_used:
                    state, time = data[node0.name][task_count - 1][-1]
                    if node0.status != state : # 删去 and duration0 - duration != time  2024/10/24
                        data[node0.name][task_count - 1].append((node0.status, float(duration0-duration)))

            for node in nodes:
                #if node.node_type is not None and node.name != system_name and node.is_basic is False and node.is_used:
                if node.node_type is not None and node.is_basic is False and node.is_used:
                    state, time = data[node.name][task_count - 1][-1]
                    now_state = node.update_status()
                    #if now_state == 'Dormant':
                    #   now_state = 'Active'
                    if now_state != state and duration0 - duration != time:
                        data[node.name][task_count - 1].append((now_state, float(duration0 - duration)))

            task_model.status = task_model.update_status()  # 更新模型状态
            
            # print(f"节点名称: {[basic_nodes0[id].name for id in basic_nodes0]}")
            # print(f"节点使用: {[basic_nodes0[id].is_used for id in basic_nodes0]}")
            # print(f"节点状态: {[basic_nodes0[id].status for id in basic_nodes0]}")
            # node0.repair_time = 0
            # print(f"剩余寿命: {[f'{basic_nodes0[id].failure_time:.2f}' for id in basic_nodes0]}")
            # print(f"维修所需: {[f'{basic_nodes0[id].repair_time:.2f}' for id in basic_nodes0]}")
            # print()
            
            if task_model.status == 'Failed':
                if not task_fail:
                    #data[system_name][task_count - 1].append(('Failed', float(duration0-duration)))
                    data['Overall_Task'][task_count - 1].append(('Failed', float(duration0-duration)))
                    task_fail = True
                    # # # print(f"任务{task_count}失败")
                # model_continue = False
                # break

        # print(f"任务{task_count}完成")
        for id in basic_nodes0:
            node0 = basic_nodes0[id]
            if node0.failure_dist.disttype == Dist.binomial or node0.failure_dist.disttype == Dist.bernoulli:
                node0.failure_time = node0.failure_time_m  # 离散节点在阶段结束时调用上阶段的剩余寿命以评估损耗，不录入节点类型
            else:
                if node0.is_used:
                    node0.last_failure_dist = node0.failure_dist   # 将之前的节点类型记录
            
            if node0.is_used:
                data[node0.name][task_count-1].append((node0.status, float(duration0-duration)))

            node0.is_cyc = False
            node0.cyc = [0, 0, 0]

        for node in nodes:
            #if node.node_type is not None and node.name != system_name and node.is_basic is False and node.is_used:
            if node.node_type is not None and node.is_basic is False and node.is_used:
                state, time = data[node.name][task_count - 1][-1]
                now_state = node.update_status()
                #if now_state == 'Dormant':
                #    now_state = 'Active'
                data[node.name][task_count - 1].append((now_state, float(duration0 - duration)))
        '''
        if not task_fail:
            data[system_name][task_count - 1].append(('Active', float(duration0-duration)))
        else:
            data[system_name][task_count - 1].append(('Failed', float(duration0-duration)))
        '''
        if not task_fail:
            data['Overall_Task'][task_count - 1].append(('Active', float(duration0-duration)))
        else:
            data['Overall_Task'][task_count - 1].append(('Failed', float(duration0-duration)))
        task_count += 1

    #print(data['1731552112678181698-1'])
    '''
    同时输出截断元件模拟和连续模拟，先拷贝一份data 2024/8/15
    '''

    data_continuous = copy.deepcopy(data)
    '''
    下面这段代码的作用是，在任务模型失效时，将(把导致失效的节点和系统)从失效时刻起全改成Failed
    如果不需要就注释掉2024/8/13
    '''
    # task_c0, time0 记录失效的阶段和时间
    task_f = False
    for task_c0 in range(task_count-1):
        size0 = len(data['Overall_Task'][task_c0])
        for j0 in range(size0 - 1):
            state0, time0 = data['Overall_Task'][task_c0][j0]
            if state0 == 'Failed':
                task_f = True
                break
        if task_f:
            break
    if task_f:
        for key in data:
            if key != 'Overall_Task':
                if data[key][task_c0]:
                    size = len(data[key][task_c0])
                    for j in range(size):
                        state, time = data[key][task_c0][size - j - 1]
                        if state in ['Failed', 'Maintenance', 'NAM','Maintenance_SOF'] and time == time0:
                            data_f[key].append(task_c0) # 系统/单元在这个阶段导致了 任务失败 12.3

        for key in data:
            if key != 'Overall_Task':
                if data_f[key]:
                    size = len(data[key][task_c0])
                    for j in range(size):
                        state, time = data[key][task_c0][size - j - 1]
                        if time >= time0:
                            del data[key][task_c0][size - j - 1]
                        
                    data[key][task_c0].append(('Failed', time0))
                    data[key][task_c0].append(data['Overall_Task'][task_c0][-1])

                    for task_c in range(task_c0+1,task_count-1):
                        data[key][task_c] = copy.deepcopy(data['Overall_Task'][task_c])
    # 2024/8/15 删除引入的表示系统状态的键值对
    #print(data)
    #print(data['X1'])
    org_data = copy.deepcopy(data)
    #下面这段代码只统计第一次失败
    '''
    for task_c0 in range(task_count-1):
        for key in data:
            if data[key][task_c0]:
                last_state, last_time = data[key][task_c0][-1]
                if data_f[key]:
                    data[key][task_c0][0] = ('Failed', 0)
                    del data[key][task_c0][1:]
                    data[key][task_c0].append(('Failed', last_time))
                else:
                    size = len(data[key][task_c0])
                    for j in range(size):
                        state, time = data[key][task_c0][j]
                        if state in ['Failed', 'Maintenance','Maintenance_SOF', 'NAM']:
                            data_f[key].append(task_c0)
                            del data[key][task_c0][j+1:]
                            data[key][task_c0].append((state, last_time))
                            break


    #print(data['X1'])
    #print()
    '''
    del data_continuous['Overall_Task']
    del data['Overall_Task']
    processed_org_data = process_data(org_data)
    processed_data = process_data(data)
    processed_data_continuous = process_data(data_continuous)
    #print(processed_data)
    return processed_data,processed_data_continuous